package com.dataextend.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.dataextend.Enum.TagCodeEnum;
import com.dataextend.Enum.TrackingEnum;
import com.dataextend.entity.HopperAnalysisRequest;
import com.dataextend.mapper.master.ClickhouseMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 *  Clickhouse 转化漏斗分析模型
 */

@Service
public class ClickhouseHopperAnalysisService {
    @Autowired
    ClickhouseMapper clickhouseMapper;


    private List<JSONObject> resolveDetail(List<String> eventCodes,String target, List<JSONObject> filterParameter, String startDate, String endDate){
        String countCalculate = "count(distinct distinct_id) as num ";
        String targetCondition = null;
        if (StringUtils.isNotEmpty(target)){
            targetCondition = target + " as logo,";
        } else {
            targetCondition = "";
        }
        String str_1 = "select t1.datadate as datadate,";
        String str_2 = null;
        if (StringUtils.isNotEmpty(target)){
            str_2 = "t1.logo as logo,count(distinct t1.distinct_id ) as users from ";
        } else {
            str_2 = "count(distinct t1.distinct_id ) as users from ";
        }

        StringBuilder targetDimension =  new StringBuilder();
        StringBuilder whereCondition = new StringBuilder();  // where限制条件
        String condition = null;  //  赋值过滤条件
        int i=1;
        for (String eventCode : eventCodes){
            String alias = "t" + String.valueOf(i);
            targetDimension.append("(select datadate,");
            targetDimension.append(targetCondition);
            targetDimension.append("distinct_id,client_time from userprofile_analysis_model where datadate >= '").append(startDate);
            targetDimension.append("' and datadate <='").append(endDate);
            targetDimension.append("' and clickevent='").append(eventCode).append("' ");             //.append("' )").append(alias);

            if (filterParameter.size()>0){    // 过滤筛选条件
                for (JSONObject obj : filterParameter){
                    String type = obj.getString("type");
                    String field = obj.getString("field");
                    String name = obj.getString("name");
                    String tag = obj.getString("tag");
                    if (type.equals("event")){
                        condition = " and (" + field + "='" + tag + "')";
                        targetDimension.append(condition);
                    } else {
                        String fieldName = "tag_" + field;
                        condition = " and (" + fieldName + "='" + tag + "')";
                        targetDimension.append(condition);
                    }
                }
            } else {
                targetDimension.append(" ");
            }
            targetDimension.append(" )").append(alias);

            if (eventCodes.size()>1 && i>=2){
                targetDimension.append(" on (t1.datadate = ").append(alias).append(".datadate and t1.distinct_id =");
                targetDimension.append(alias).append(".distinct_id) ");
                String aliasBefore = "t" + String.valueOf(i-1);
                whereCondition.append(alias).append(".client_time > ").append(aliasBefore).append(".client_time and ");
            }

            if (eventCodes.size()>1 && i< eventCodes.size()){
                targetDimension.append(" inner join ");
            }
            i+=1;
        }

        String str_3 = null;
        if (StringUtils.isNotEmpty(target)){
            str_3 = " group by t1.datadate,t1.logo order by t1.datadate,t1.logo";
        } else {
            str_3 = " group by t1.datadate" + " order by t1.datadate";
        }

        String where = null;  // 限制条件 t2.client_time>t1.client_time

        String search_sql = null;   // 查询的SQL语句
        if (eventCodes.size()>1){    // 首次查询不加where时间限制
            where = " where (" + whereCondition.toString().substring(0, whereCondition.toString().length()-4) + ")";
            search_sql = str_1 + str_2 + targetDimension.toString() + where + str_3;
        } else {
            search_sql = str_1 + str_2 + targetDimension.toString() + str_3;
        }

        //System.out.println("--------search_sql:" + search_sql);
        List<JSONObject> searchResult = clickhouseMapper.hopperAnalysis(search_sql);

        return searchResult;
    }



    /***
     *  计算包含的分组
     */
    private List<String> targetNames(JSONObject detail){
        List<String> returnResult = new ArrayList<>();
        List<JSONObject> contents = (List<JSONObject>) detail.get("content");
        for (JSONObject obj :contents){
            returnResult.add(obj.getString("logo"));
        }
        return returnResult.stream().distinct().collect(Collectors.toList());
    }

    /***
     *  计算包含的分组 (另一种入参)
     */
    private List<String> targetNames_(List<JSONObject> detail){
        List<String> returnResult = new ArrayList<>();
        for (JSONObject obj : detail){
            returnResult.add(obj.getString("legend"));
        }
        return returnResult;
    }



    /***
     *  计算包含的所有日期
     */
    private List<String> allDays(JSONObject detail){
        List<String> returnResult = new ArrayList<>();
        List<JSONObject> contents = (List<JSONObject>) detail.get("content");
        for (JSONObject obj :contents){
            returnResult.add(obj.getString("datadate"));
        }
        return returnResult.stream().distinct().collect(Collectors.toList());
    }




    /**
     *  解析查询的详情 —— 计算转化趋势
     */
    private List<JSONObject> resolveHopper(List<JSONObject> searchDetail, String target){
        List<String> targets = null;
        List<String> alldays = null;
        if (target.equals("1")){
            targets = targetNames(searchDetail.get(0));
            alldays = allDays(searchDetail.get(0));
        } else {
            alldays = allDays(searchDetail.get(0));
        }
//        System.out.println("------------targets:" + targets);
//        System.out.println("------------alldays:" + alldays);

//        JSONArray allInfos = new JSONArray();
        List<JSONObject> allInfos = new ArrayList<>();
        if (target.equals("1")) {        // 如果存在分组的情况
            for (String tar :targets) {           //  所有的分组
                for (String datadate:alldays) {  // 所有的日期
                    JSONObject everyDetailObj = new JSONObject(true);
                    JSONArray overwiew = new JSONArray();
                    everyDetailObj.put("datadate", datadate);
                    if (tar.contains("_")){
                        everyDetailObj.put("legend", TagCodeEnum.getName(tar));
                    } else {
                        everyDetailObj.put("legend", tar);
                    }

                    Long beforeStepUsers = 100L;
                    for (JSONObject obj : searchDetail){
                        String nowStep = obj.getString("step");
                        List<JSONObject> details = (List<JSONObject>) obj.get("content");
                        for (JSONObject detailobj : details){
                            JSONObject saveDetail = new JSONObject(true);
                            String obj_datadate = detailobj.getString("datadate");
                            String obj_logo = detailobj.getString("logo");
                            Long obj_user = detailobj.getLong("users");
                            if (tar.equals(obj_logo) && datadate.equals(obj_datadate)){
                                saveDetail.put("step", nowStep);
                                saveDetail.put("users", obj_user);
                                if (nowStep.equals("1")){
                                    beforeStepUsers = obj_user;
                                    saveDetail.put("rate", "100");
                                } else {
                                    saveDetail.put("rate", String.format("%.2f", (double) obj_user / beforeStepUsers * 100));
                                    beforeStepUsers = obj_user;
                                }
                                overwiew.add(saveDetail);
                            }

                        }
                    }
                    everyDetailObj.put("overview", overwiew);
                    //System.out.println("----------------everyDetailObj:" + everyDetailObj);
                    allInfos.add(everyDetailObj);
                }
            }
        } else {        // 如果没有分组
            for (String datadate:alldays){
                JSONObject everyDetailObj = new JSONObject(true);
                everyDetailObj.put("datadate", datadate);
                JSONArray overwiew = new JSONArray();
                Long beforeStepUsers = 100L;
                for (JSONObject obj : searchDetail){
                    String nowStep = obj.getString("step");
                    List<JSONObject> details = (List<JSONObject>) obj.get("content");
                    for (JSONObject detailobj : details){
                        JSONObject saveDetail = new JSONObject(true);
                        String obj_datadate = detailobj.getString("datadate");
                        Long obj_user = detailobj.getLong("users");
                        if (datadate.equals(obj_datadate)){
                            saveDetail.put("step", nowStep);
                            saveDetail.put("users", obj_user);
                            if (nowStep.equals("1")){
                                beforeStepUsers = obj_user;
                                saveDetail.put("rate", "100%");
                            } else {
                                saveDetail.put("rate", String.format("%.2f", (double) obj_user / beforeStepUsers * 100) + "%");
                                beforeStepUsers = obj_user;
                            }
                            overwiew.add(saveDetail);
                        }
                    }
                }
                everyDetailObj.put("overview", overwiew);
                allInfos.add(everyDetailObj);
            }
        }
//        System.out.println("----------------allInfos:" + allInfos);

        return allInfos;
    }



    /**
     *  计算转化 - 全部信息
     */
    private List<JSONObject> resolveTransformAll(List<JSONObject> numUserS, Integer cnt){
        // cnt 有几步骤
        List<JSONObject> resultReturn = new ArrayList<>();
        JSONObject allInfo = new JSONObject(true);

        List<Long> allNum = new ArrayList<>();
        for (int i=0; i<cnt; i++){
            Long allSum = 0L;
            for (JSONObject obj : numUserS){
                JSONObject detail = new JSONObject(true);
                detail.put("type", obj.getString("type"));
                detail.put("num", (List<Long>) obj.get("num"));
                List<Long> num = (List<Long>) obj.get("num");
                resultReturn.add(detail);
                allSum+= num.get(i);
            }
            allNum.add(allSum);
        }
        allInfo.put("type", "全部");
        allInfo.put("num", allNum);
        resultReturn.add(allInfo);

        return resultReturn.stream().distinct().collect(Collectors.toList());
    }




    /**
     *  解析查询的详情 —— 计算转化
     */
    private JSONObject resolveTransform(List<JSONObject> searchDetail, List<String> legendCode, String target){
        JSONObject resultReturn = new JSONObject(true);
        List<String> legendName = new ArrayList<>();  // 存储图例的名称
        List<String> groupName = targetNames_(searchDetail);  // 分组的组别
        for (String legengd :legendCode){
            legendName.add(TrackingEnum.getName(legengd));
        }

        resultReturn.put("legend", legendName);
        // System.out.println("-----------------searchDetail:" + searchDetail);

        if (target.equals("1")){         // 如果存在分组的情况
            List<Long> numUser = new ArrayList<>();
            List<JSONObject> numUserS = new ArrayList<>();

            for (String legend : groupName){  // 组别名称 男 女
                List<Long> groupNum = new ArrayList<>();
                JSONObject detail = new JSONObject(true);
                for (int i=0; i<legendName.size(); i++) {  // 总共有多少步骤  i=0
                    Long allUsers = 0L;
                    for (JSONObject obj : searchDetail){
                        String legend_now = obj.getString("legend");
                        List<JSONObject> details = (List<JSONObject>) obj.get("overview");
                        if (legend.equals(legend_now)){
                            for (JSONObject detailobj : details){
                                String step_now = detailobj.getString("step");
                                Long obj_user = detailobj.getLong("users");
                                if (String.valueOf(i+1).equals(step_now)){
                                    allUsers+=obj_user;
                                }
                            }
                        }
                    }
                    groupNum.add(allUsers);
                }
                detail.put("type", legend);
                detail.put("num", groupNum);
//                System.out.println("--------------detail:" + detail);
                numUserS.add(detail);
            }

            List<JSONObject> numAllUser = resolveTransformAll(numUserS.stream().distinct().collect(Collectors.toList()), legendCode.size());
            resultReturn.put("numUser", numAllUser);
//            System.out.println("--------------numUserS:" + numUserS.stream().distinct().collect(Collectors.toList()));

        } else {                        // 如果没有分组
            List<Long> numUser = new ArrayList<>();
            List<JSONObject> numUserS = new ArrayList<>();
            for (int i=0; i<legendName.size(); i++){
                JSONObject detail = new JSONObject(true);
                Long allUsers = 0L;
                for (JSONObject obj : searchDetail){
                    List<JSONObject> details = (List<JSONObject>) obj.get("overview");
                    for (JSONObject detailobj : details){
                        String step_now = detailobj.getString("step");
                        Long obj_user = detailobj.getLong("users");
                        if (String.valueOf(i+1).equals(step_now)){
                            allUsers+=obj_user;
                        }
                    }
                }
                detail.put("num", allUsers);
                numUserS.add(detail);
                numUser.add(allUsers);
            }

            String rate = String.format("%.2f", (double) numUser.get(numUser.size()-1) / numUser.get(0) * 100);
            resultReturn.put("numUser", numUserS);
            resultReturn.put("rate", rate + "%");
        }

        return resultReturn;
    }


    /**
     *  请求返回函数
     */
    public JSONObject hopperAnalysis(HopperAnalysisRequest hopperAnalysisRequest){

        JSONObject resultReturn = new JSONObject(true);
        List<String> events = new ArrayList<>();
        int step =1;
        List<JSONObject> searchDetail = new ArrayList<>();
        for (String eventCode :hopperAnalysisRequest.getEventCodes()){
            JSONObject detail = new JSONObject(true);
            events.add(eventCode);
            detail.put("step", String.valueOf(step));
            detail.put("content", resolveDetail(events, hopperAnalysisRequest.getTarget(), hopperAnalysisRequest.getFilterParameter(), hopperAnalysisRequest.getStartDate(),
                    hopperAnalysisRequest.getEndDate()));
            searchDetail.add(detail);
            step+=1;
        }
        System.out.println("----------:" + searchDetail);   // 查询clickhouse的结果明细

        List<JSONObject> transformTendency = new ArrayList<>();   // 转化趋势
        if (StringUtils.isNotEmpty(hopperAnalysisRequest.getTarget())){
            transformTendency = resolveHopper(searchDetail, "1");
        } else {
            transformTendency = resolveHopper(searchDetail, "2");
        }
        resultReturn.put("transformTendency", transformTendency);


        JSONObject transform = new JSONObject(true);    // 转化
        if (StringUtils.isNotEmpty(hopperAnalysisRequest.getTarget())){
            transform = resolveTransform(transformTendency, hopperAnalysisRequest.getEventCodes(),"1");
        } else {
            transform = resolveTransform(transformTendency, hopperAnalysisRequest.getEventCodes(),"2");
        }
        resultReturn.put("transform", transform);

        return resultReturn;
    }

}
